import type { NamePath } from "antd/lib/form/interface";
import type { FormActionType, FormProps, FormSchemaInner as FormSchema, UseFormReturnType } from "../types/form";
import { isProdMode } from "@/utils/env";
import { useEffect, useRef } from "react";
import { nextTick } from "@/utils";

type Props = Partial<FormProps>;

export function useForm(props?: Props): UseFormReturnType {
	const formRef = useRef<any>(null);
	const loadedRef = useRef<boolean>(false);

	useEffect(() => {
		return () => {
			formRef.current = null;
			loadedRef.current = false;
		};
	}, []);

	async function getForm() {
		const form = formRef.current;
		if (!form)
			console.error(
				"The form instance has not been obtained, please make sure that the form has been rendered when performing the form operation!"
			);
		await nextTick();
		return form as FormActionType;
	}

	function register(instance: FormActionType) {
		if (loadedRef.current && isProdMode() && instance === formRef.current) return;
		formRef.current = instance;
		props && instance.setProps(props);
		loadedRef.current = true;
	}

	const methods: FormActionType = {
		/** Ant Form */
		getFieldError: async (name: NamePath) => {
			const form = await getForm();
			return form.getFieldError(name);
		},
		getFieldInstance: async (name: NamePath) => {
			const form = await getForm();
			return form.getFieldInstance(name);
		},
		getFieldsError: async (nameList?: NamePath[]) => {
			const form = await getForm();
			return form.getFieldsError(nameList);
		},
		getFieldsValue: async (
			nameList?: true | NamePath[],
			filterFunc?: (meta: { touched: boolean; validating: boolean }) => boolean
		) => {
			const form = await getForm();
			return form.getFieldsValue(nameList!, filterFunc);
		},
		getFieldValue: async (name: NamePath) => {
			const form = await getForm();
			form.getFieldValue(name);
		},
		isFieldsTouched: async (...args) => {
			const form = await getForm();
			form.isFieldsTouched(args);
		},
		isFieldTouched: async (name: NamePath) => {
			const form = await getForm();
			return form.isFieldTouched(name);
		},
		isFieldValidating: async (name: NamePath) => {
			const form = await getForm();
			return form.isFieldValidating(name);
		},
		resetFields: async (fields?: NamePath[]) => {
			const form = await getForm();
			form.resetFields(fields);
		},
		scrollToField: async (name: NamePath, options: ScrollOptions) => {
			const form = await getForm();
			form.scrollToField(name, options);
		},
		setFields: async (fields: any[]) => {
			const form = await getForm();
			form.setFields(fields);
		},
		setFieldValue: async (name: NamePath, value: any) => {
			const form = await getForm();
			form.setFieldValue(name, value);
		},
		setFieldsValue: async (values: any) => {
			const form = await getForm();
			form.setFieldsValue(values);
		},
		submit: async () => {
			const form = await getForm();
			form.submit();
		},
		validateFields: async (nameList?: NamePath[]) => {
			const form = await getForm();
			return await form.validateFields(nameList);
		},
		/** Custom */
		setProps: async (formProps: Partial<FormProps>) => {
			const form = await getForm();
			form.setProps(formProps);
		},
		updateSchema: async (data: Partial<FormSchema> | Partial<FormSchema>[]) => {
			const form = await getForm();
			form.updateSchema(data);
		},
		resetSchema: async (data: Partial<FormSchema> | Partial<FormSchema>[]) => {
			const form = await getForm();
			form.resetSchema(data);
		},
		handleSubmit: async (): Promise<void> => {
			const form = await getForm();
			return form.handleSubmit();
		}
	};

	return [register, methods];
}
